using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace SymAutomate
{
    /// <summary>
    /// Error Numbers 720-749; Reference file ErrorNumbers.txt for more information.
    /// 720 Error: The value for ::SLP:: command must be a number.
    /// 721 Error: The value for ::CIF:: command can only be BEGIN or END.
    /// </summary>
    public class RawCommandParameter
    {
        public enum RawCommandParameterSegmentType
        {
            AsciiCommunication,
            Sleep,
            CommandIgnoreFailure
        }

        public class RawCommandParameterSegment
        {
            private string __Prompt;
            private object __Value;
            private RawCommandParameterSegmentType __RawCommandParameterSegmentType;

            public string Prompt { get { return __Prompt; } set { __Prompt = value; } }
            public object Value { get { return __Value; } set { __Value = value; } }
            public RawCommandParameterSegmentType RawCommandParameterSegmentType { get { return __RawCommandParameterSegmentType; } set { __Value = __RawCommandParameterSegmentType; } }

            public RawCommandParameterSegment(string _Prompt, object _Value, RawCommandParameterSegmentType _RawCommandParameterSegmentType)
            {
                __Prompt = _Prompt;
                __Value = _Value;
                __RawCommandParameterSegmentType = _RawCommandParameterSegmentType;
            }
        }

        private List<RawCommandParameterSegment> __RawCommandParameterSegmentCollection;
        private string __RawCommand;
        private bool __IsValid;

        public string RawCommand { get { return __RawCommand; } }
        public List<RawCommandParameterSegment> RawCommandParameterSegmentCollection { get { return __RawCommandParameterSegmentCollection; } set { __RawCommandParameterSegmentCollection = value; } }
        public bool IsValid() { return __IsValid; }

        public RawCommandParameter()
        {
            __RawCommandParameterSegmentCollection = new List<RawCommandParameterSegment>();
        }

        public RawCommandParameter(string _RawCommand)
        {
            __RawCommand = _RawCommand;
            __IsValid = false;
            __RawCommandParameterSegmentCollection = new List<RawCommandParameterSegment>();
        }

        public bool ParseRawCommand()
        {
            if (!string.IsNullOrEmpty(__RawCommand))
            {
                if (!Regex.IsMatch(__RawCommand, @"^{[^\r\n{}]*?}{[^\r\n{}]*?}(,{[^\r\n{}]*?}{[^\r\n{}]*?})+$"))
                    return __IsValid = false;

                MatchCollection _MatchCollection;
                Regex _Regex;

                //first segment
                _Regex = new Regex(@"^{([^\r\n{}]*?)}{([^\r\n{}]*?)}");
                _MatchCollection = _Regex.Matches(__RawCommand);
                this.AddRawCommandParameterSegment(_MatchCollection[0].Groups[1].ToString(), _MatchCollection[0].Groups[2].ToString());

                //rest of the segments (if any)
                _Regex = new Regex(@",{([^\r\n{}]*?)}{([^\r\n{}]*?)}");
                _MatchCollection = _Regex.Matches(__RawCommand);
                for (int i = 0; i < _MatchCollection.Count; i++)
                {
                    this.AddRawCommandParameterSegment(_MatchCollection[i].Groups[1].ToString(), _MatchCollection[i].Groups[2].ToString());
                }

                bool _CIFBeginIsOpen = false;
                for (int i = 0; i < __RawCommandParameterSegmentCollection.Count; i++)
                {
                    RawCommandParameter.RawCommandParameterSegment _RawCommandParameterSegment = __RawCommandParameterSegmentCollection[i];
                    if (_RawCommandParameterSegment.RawCommandParameterSegmentType == RawCommandParameter.RawCommandParameterSegmentType.Sleep)
                    {
                        int _IgnoreInt;
                        if (!int.TryParse(_RawCommandParameterSegment.Value.ToString(), out _IgnoreInt))
                            throw new ReturnException("720 Error: The value for ::SLP:: command must be a number." + Environment.NewLine + RawCommandParameter.GetFailedPromptLocation(__RawCommandParameterSegmentCollection, i));
                    }
                    else if (_RawCommandParameterSegment.RawCommandParameterSegmentType == RawCommandParameter.RawCommandParameterSegmentType.CommandIgnoreFailure)
                    {
                        if (_RawCommandParameterSegment.Value.ToString().ToLower() != "begin" && _RawCommandParameterSegment.Value.ToString().ToLower() != "end")
                            throw new ReturnException("721 Error: The value for ::CIF:: command can only be BEGIN or END." + Environment.NewLine + RawCommandParameter.GetFailedPromptLocation(__RawCommandParameterSegmentCollection, i));

                        //if END is found and BEGIN is not found before
                        if (_RawCommandParameterSegment.Value.ToString().ToLower() == "end" && !_CIFBeginIsOpen)
                            throw new ReturnException("722 Error: The ::CIF:: BEGIN/END tags missing or not in correct order." + Environment.NewLine + RawCommandParameter.GetFailedPromptLocation(__RawCommandParameterSegmentCollection, i));
                        
                        //if BEGIN is found end BEGIN is already found before
                        if (_RawCommandParameterSegment.Value.ToString().ToLower() == "begin" && _CIFBeginIsOpen)
                            throw new ReturnException("722 Error: The ::CIF:: BEGIN/END tags missing or not in correct order." + Environment.NewLine + RawCommandParameter.GetFailedPromptLocation(__RawCommandParameterSegmentCollection, i));

                        //open the BEGIN flag
                        if (_RawCommandParameterSegment.Value.ToString().ToLower() == "begin")
                            _CIFBeginIsOpen = true;
                        //close the BEGIN flag
                        if (_RawCommandParameterSegment.Value.ToString().ToLower() == "end")
                            _CIFBeginIsOpen = false;    
                    }
                }
                //if after loocking at all prompts BEGIN is still open
                if (_CIFBeginIsOpen)
                    throw new ReturnException("722 Error: The ::CIF:: BEGIN/END tags missing or not in correct order.");
                        
            }
            return true;
        }

        private void AddRawCommandParameterSegment(string _Prompt, string _Value)
        {
            if (_Prompt.ToLower() == "::CIF::".ToLower())
            {
                __RawCommandParameterSegmentCollection.Add(new RawCommandParameterSegment("::CIF::", _Value.ToUpper(), RawCommandParameterSegmentType.CommandIgnoreFailure));
            }
            else if (_Prompt.ToLower() == "::SLP::".ToLower())
            {
                __RawCommandParameterSegmentCollection.Add(new RawCommandParameterSegment("::SLP::", _Value, RawCommandParameterSegmentType.Sleep));
            }
            else
            {
                __RawCommandParameterSegmentCollection.Add(new RawCommandParameterSegment(_Prompt, _Value, RawCommandParameterSegmentType.AsciiCommunication));
            }

            //Console.Write(_Prompt);
            //Console.Write("-");
            //Console.WriteLine(_Value);
        }

        public static string GetFailedPromptLocation(List<RawCommandParameterSegment> _RawCommandParameterSegmentCollection, int _Index)
        {
            string _ReturnText = string.Empty;
            int _ErrorStartingLineIndex = 0;

            if (_Index > 1)
            {
                _ReturnText += "...";
                _ErrorStartingLineIndex += 3;
            }
            if (_Index > 0)
            {
                _ReturnText += "{" +
                    _RawCommandParameterSegmentCollection[_Index - 1].Prompt +
                    "}{" +
                    _RawCommandParameterSegmentCollection[_Index - 1].Value +
                    "},";
                _ErrorStartingLineIndex += 1 +
                    _RawCommandParameterSegmentCollection[_Index - 1].Prompt.Length +
                    2 +
                    _RawCommandParameterSegmentCollection[_Index - 1].Value.ToString().Length +
                    2;
            }
            _ReturnText += "{" +
                _RawCommandParameterSegmentCollection[_Index].Prompt +
                "}{" +
                _RawCommandParameterSegmentCollection[_Index].Value +
                "}";
            _ErrorStartingLineIndex += 1;
            if (_Index < _RawCommandParameterSegmentCollection.Count - 1)
            {
                _ReturnText += ",{" +
                    _RawCommandParameterSegmentCollection[_Index + 1].Prompt +
                    "}{" +
                    _RawCommandParameterSegmentCollection[_Index + 1].Value +
                    "}";
            }
            if (_Index < _RawCommandParameterSegmentCollection.Count - 2)
            {
                _ReturnText += "...";
            }
            _ReturnText += Environment.NewLine;
            _ReturnText += string.Empty.ToString().PadLeft(_ErrorStartingLineIndex, '-');
            _ReturnText += "|";

            return _ReturnText;
        }

    }
}
